package tm.testing;


import java.util.HashMap;
import com.jme.curve.Curve;
import com.jme.curve.CurveController;
import com.jme.math.Vector3f;
import com.jme.scene.Node;
import com.jme.scene.Spatial;

/**
 * This Class represents an implementation of a train consisting out of multiple
 * moving parts. The given geometry must match the given specifications. A train
 * must stand on only moving parts. For example a pantograph has to belong to the
 * particular car. Every moving part must be named the following way: <code>name.###"
 * </code>. The number defines the position of the moving part relative to the y axis.
 * (in modeler) So the first car would be called <code>car.001</code>, the second
 * <code>car.002</code> and so on. If there is a bogie between them, it would be called
 * <code>bogie.002</code> and the second car <code>car.003</code>. The whole train must
 * be aligned pointing forward along y axis in modeler.
 * 
 * @author Sebastian Haas
 * @see OffsetCurveController
 *
 */
public class TrainController {
	private Node movernode;
    private Curve curve;
    
    private boolean startup = true;
    private int currentstartup = 0;
    
    private HashMap<Spatial,OffsetCurveController> partscc;
    private HashMap<Spatial, Vector3f> partsdiff;
    private HashMap<Integer, Spatial> partsorder;
    
    private float speed;

    /**
     * Sets up an calculates the basic information that will be needed by
     * the TrainController.
     * 
     * @param c The curve this train will be placed and moving on
     * @param mover The train's geometry information
     */
    public TrainController(Curve c, Node mover) {
        this.curve = c;
        this.movernode = mover;
        partscc = new HashMap<Spatial, OffsetCurveController>();
        partsdiff = new HashMap<Spatial, Vector3f>();
        partsorder = new HashMap<Integer, Spatial>();
        
        //Note that the train doesn't get displayed correctly if not moving.
        // TODO implement a way to place a train in correct order on curve
        
        //Separate the train into it's moving parts:
        for(int i=0; i<movernode.getChildren().size(); i++) {
        	Spatial tmp = movernode.getChild(i);
        	int order = Integer.valueOf(tmp.getName().substring(tmp.getName().length()-3));
        	partsorder.put((order-1), tmp);
        	
        	//Assign an OffsetCurveController to each moving part:
        	OffsetCurveController cc = new OffsetCurveController(curve, tmp);
        	//Set the OffsetCurveController's offset to match the model's y translation:
            cc.setOffset(new Vector3f(0,tmp.getLocalTranslation().y,0));
        	cc.setSpeed(0);
            cc.setRepeatType(CurveController.RT_CYCLE);
            cc.setAutoRotation(true);
            cc.setOrientationPrecision(0.01f);
            cc.setSpeed(0);
            tmp.addController(cc);
            
            
            partscc.put(tmp, cc);
        }
        
        //Calculate translation differences between the train's moving parts
        for(int i=0; i<partsorder.size(); i++) {
        	
        	Spatial tmp = partsorder.get(i);
        	Vector3f diff;
        	if(i==0) {
        		diff = null;
        	} else {
        		diff = partsorder.get(i-1).getLocalTranslation().subtract(tmp.getLocalTranslation());
        	}
        	partsdiff.put(tmp, diff);
        }
		
        System.out.println(partsdiff);
		
    }
    
    /**
     * This method needs to be called every frame in order to make TrainController working.
     */
    public void update() {
    	if(startup) {
    		Spatial tmp = partsorder.get(currentstartup);
    		if(currentstartup==0) {
    			partscc.get(tmp).setSpeed(speed);
    			if(currentstartup < partsorder.size()-1) {
    				currentstartup++;
    			} else {
    				currentstartup = -1;
    				startup = false;
    			}
    		} else {
	    		if((partsorder.get(currentstartup-1).getLocalTranslation().
	    				subtract(tmp.getLocalTranslation())).x
	    				>= partsdiff.get(tmp).x) {
	    			partscc.get(tmp).setSpeed(speed);
	    			if(currentstartup < partsorder.size()-1) {
	    				currentstartup++;
	    			} else {
	    				currentstartup = -1;
	    				startup = false;
	    			}
	    		}
    		}
    	}
    }
   
    /**
     * 
     * @return Returns the train's current speed calibration
     */
    public float getSpeed() {
    	return speed;
    }
    
    /**
     * Sets this train's speed calibration
     * 
     * @param speed The speed setting for the train
     */
    public void setSpeed(float speed) {
    	this.speed = speed;
    }
}